to select ↑↓ to navigate
Doppiobox

Doppiobox

Open in ChatGPT
Ask ChatGPT about this page
Open in Claude
Ask Claude about this page

The benchspace CLI

Status — read this first. The CLI lives at cli/benchspace_cli/ but is not tracked in git and its .py source is no longer present — only compiled .pyc bytecode remains (cli/benchspace_cli/__pycache__/*.cpython-311.pyc). The backend RPC method it calls, benchspace.api.cli.list_dev_boxes, does not exist in the current control-plane source (benchspace/api/ has no cli.py). Treat this page as documentation of an orphaned / work-in-progress prototype, reconstructed from the bytecode's embedded strings and docstrings — not from live source. Everything below is marked accordingly.

What it is

benchspace is a small command-line tool — "Codespaces for Frappe" — that lets a developer manage hosted Dev Boxes for the current app + branch straight from their terminal, without opening the dashboard. It is built with Typer (the CLI framework) and rich for pretty console tables.

The defining idea is that a Dev Box is bound to a group derived from where you are: the combination of the logged-in user, the git app, and the checked-out branch. Run a command inside a repo on branch feature-x and the CLI talks only about the box for that (owner, app, feature-x) slice — mirroring a parallel-worktree workflow.

Package layout (4 modules)

Module Role
main.py Typer entry point — defines the commands (login, whoami, ls).
api.py BenchspaceClient — thin token-auth REST client for the hosted Frappe site.
config.py Read/write ~/.benchspace/config.toml (server URL + API token).
context.py Resolve the {owner}:{app}:{branch} group from the current git working directory.

diagram

Commands

All three are declared in main.py (Typer app, no_args_is_help=True).

Command What it does
benchspace login Prompts for the server URL and API token (api_key:api_secret, input hidden), then saves them to ~/.benchspace/config.toml with chmod 600.
benchspace whoami Prints the authenticated user (calls frappe.auth.get_logged_user) and the resolved group for the current directory (User: / App: / Branch: / Group:). If the group can't be resolved it prints Group: unavailable (<reason>).
benchspace ls Lists the Dev Boxes in the current (owner, app, branch) group as a rich table with columns Slug · Status · Branch · Site URL. Prints No Dev Boxes for group <…> when empty.

The bytecode shows the command function for the listing is registered as ls; the embedded help text ("List the Dev Boxes in the current (owner, app, branch) group.") confirms its behavior.

Configuration — config.py

  • Default path: ~/.benchspace/config.toml. Override with the BENCHSPACE_CONFIG env var (used by tests and to avoid clobbering a real prod config).

  • File format:

    [server]
    url = "https://boxes.buildwithhussain.com"
    token = "api_key:api_secret"
    
  • read_config() raises a clean error when the file is missing (No benchspace config at <path>. Run \benchspace login` first.) or incomplete (Incomplete config at . Run `benchspace login` again.`).

  • write_config() creates ~/.benchspace/ (parents=True, exist_ok=True), writes the TOML, and **chmod 600**s it. It rejects URL/token values containing quotes or newlines.

  • Parsed with the stdlib tomllib; modelled as a @dataclass Config(server, token).

API client — api.py

BenchspaceClient is a "thin REST client for the hosted benchspace Frappe site (token auth)". It wraps a requests.Session with headers:

Authorization: token <token>
Accept: application/json
  • _call(method, dotted_path, params) → issues a request to /api/method/<dotted_path> and raises BenchspaceAPIError on a transport failure (Could not reach <endpoint> from <…>) or a non-2xx response (surfacing the server's message/error details).
  • whoami()frappe.auth.get_logged_user.
  • list_dev_boxes(group_key)benchspace.api.cli.list_dev_boxes.

Group resolution — context.py

A group is identified by {owner}:{app}:{branch}:

  • owner — the logged-in benchspace user, resolved from the API (not git).
  • app — derived from the git remote / repo folder (derive_app_name from git remote get-url origin and git rev-parse --show-toplevel).
  • branch — the currently checked-out branch (git rev-parse --abbrev-ref HEAD).

Two domain errors give clean CLI messages instead of tracebacks:

Exception When Message
NotAGitRepoError cwd is not inside a git repo (or git not installed) not inside a git repository / git is not installed or not on PATH
DetachedHeadError HEAD is detached (no branch to key the group on) HEAD is detached — check out a named branch to use benchspace

diagram

Typical session

benchspace login            # save server URL + API token to ~/.benchspace/config.toml (600)
cd ~/code/my-frappe-app     # a git repo on the branch you care about
benchspace whoami           # User / App / Branch / Group
benchspace ls               # Dev Boxes for this owner:app:branch group

Gaps & follow-ups

  • Source (.py) is missing and untracked — only .pyc remain. Recover or re-commit the source.
  • The backend method benchspace.api.cli.list_dev_boxes is not in the current control-plane; the CLI cannot function end-to-end until it is added (see page 06 — Task orchestration and page 07 — Frappe data model for where a benchspace/api/cli.py would live).
  • No packaging metadata (pyproject.toml/setup.py) was found under cli/, so install/entry-point wiring is unconfirmed.

See also: 01 Overview, 06 Task orchestration, 10 Dashboard (the GUI equivalent of these commands).

Last updated 1 month ago
Was this helpful?
Thanks!